package futbol.tacticas.concursantes.TacticaCaccy;

import java.awt.Color;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;

import futbol.tacticas.Comando;
import futbol.tacticas.ComandoGolpearBola;
import futbol.tacticas.ComandoIrA;


public class EscuadraMuralla extends Defense {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static Logger 			log = Logger.getLogger(EscuadraMuralla.class);

	int[] 							integrantes;
	Point2D[] 						contrarios;
	Point2D.Double					porteriaContraria;
	Point2D.Double					porteria;
	double[][] 						posicionesMarcar;
	Ball 					pelotaActual;
	Vector<AttSkills> 	rebotadors;
	Skills 					jugadorPorter;
	int[] 							jugadoresMarcadores;
	int[] 							contrariosMarcados;
	Play[] 			interceptores;
	
	int[][] 						paresMarcaje;
		
	boolean							regateado = false;
	
	double[][]						posicionsInicials =
								{
									{-50,	-60,    4}, // 0
									{-50,	60,		4}, // 1
									{-70,	0,		6}, // 2
									{-50,	 25,	4}, // 3
									{-50,	-20,	4}, // 4
									{-40,	 30,	4}, // 5
									{-90,	-70,	4}, // 6
									{-90,	 70,	4}, // 7
									{-100,	  0,	4}, // 8
									{-120,	-35,	4}, // 9
									{-120,	 35,	4}, // 10
								};
	
	public EscuadraMuralla(Manager tecnico) {
		super(tecnico);
	}
	
	public void setPorter(Skills porter)
	{
		jugadorPorter = porter;
	}
	
	@Override
	public boolean cerrarEscuadra()
	{ 
		//log.debug("cerrarEscuadra start.");
		
		if(jugadorPorter == null)
			throw new java.lang.IllegalArgumentException("Cal setterjar el porter abans!");
		
		porteriaContraria = new Point2D.Double(160,0);
		
		Skills[] jugs = tec.getAlineacion();
		
		rebotadors = new Vector<AttSkills>();
		for(Skills jug : jugs)
			if (jug instanceof AttSkills)
				rebotadors.add( (AttSkills) jug);
		
		for(int i=0; i<size(); i++)
		{
			get(i).xInicial = posicionsInicials[i][0];
			get(i).yInicial = posicionsInicials[i][1];
			get(i).fuerza   =(int) Math.floor(posicionsInicials[i][2]);
			
			//log.debug("inicial: -"+get(i).numero+"- "+get(i).xInicial+" "+get(i).yInicial);
		}

		//log.debug("cerrarEscuadra end.");
		return true;
	}

	@Override
	public Vector<Comando> getMejorJugada()
	{
		//log.debug("getMejorJugada START");
		
		int i;

		Vector<Comando>					cmds = null;
		
		sj = tec.getUltimaSJ();
		contrarios = sj.getContrario();
		pelotaActual = tec.getMiPelota();

		//log.debug("codi comu");
		if(cmds!=null)
		{
			cmds.clear();
			cmds = null;
		}
		cmds = new Vector<Comando>();
		
		for(Skills p : this)
			cmds.add( tornaPosicioInicial1(p) );
		
		interceptores = tec.getMejoresInterceptores();
		
		
		if(getContrariosDentroAreaCritica() != null){
			contrariosMarcados = getContrariosDentroAreaCritica();
			if(contrariosMarcados.length <= size()){
				jugadoresMarcadores = new int[contrariosMarcados.length];
				for(i =0; i<contrariosMarcados.length; i++ ){
					//log.debug("< Contrario a marcar:"+contrariosMarcados[i]);
					jugadoresMarcadores[i] = get(i).numero;
				}
			}
			else
			{
				jugadoresMarcadores = new int[size()];
				for(i =0; i<size(); i++ ){
					//log.debug("> Contrario a marcar:"+contrariosMarcados[i]);
					jugadoresMarcadores[i] = get(i).numero;
					contrariosMarcados = FutbolTools.arrayCopy(contrariosMarcados, this.size());
				}
				
			}
			//log.debug(jugadoresMarcadores.length + " ### " + contrariosMarcados.length);
			paresMarcaje  		= tec.decidirMarcaje(jugadoresMarcadores, contrariosMarcados);
			
		}

		
		
		for(i=0; i<size(); i++)
		{
			Skills jug = get(i);
			
			//log.debug("codi jugador: " + jug.numero);
			
			boolean tenemos = (tec.tenemosPelota() > 0 );
			boolean tengo	= (interceptores[0].indiceJugador == jug.numero || interceptores[1].indiceJugador == jug.numero);
			
		
			if(tengo)
			{	// TENGO i TENEMOS
				//log.debug("tengo - tenemos");
			
				if(jug.distance(pelotaActual) <= 10)
				{	// tengo la pelota en los pies
					Vector<Comando> cmd;
					
					if( (cmd = tirCriticPorteria(jug)) != null )
						cmds.addAll( cmd );
					else
					{
						if( (cmd = tirSegurPorteria(jug)) != null )
							cmds.addAll( cmd );
						else
						{
							if( (cmd = paseCriticRebotadors(jug)) != null )
								cmds.addAll( cmd );
							else
							{
								if( (cmd = paseSegurRebotadors(jug)) != null )
									cmds.addAll( cmd );
								else
								{
									//log.debug("pase segur soloDelante");
									
									int jugPase = tec.paseSegur(jug, 20, true);
									
									if(jug.numero != jugPase && tec.getRondaDeUltimoGol()-tec.getRonda() < -10)
									{
										double[] pase = FutbolTools.pasePreciso(jug, pelotaActual, jugPase);
										
										cmds.add( new ComandoGolpearBola(jug.numero, pase[0], pase[1]) );
									}
									else
									{
										//log.debug("corre forrest corre");
										
										if(!emPrenenLaPilota(jug,3) && !tec.getRegateadorEnRonda())
										{
											//log.debug("soc regatejador - regatejar");
											cmds.addAll( regatearAPorteria(jug) );
											tec.setRegateadorEnRonda(true);
										}
										else
										{
											
											//log.debug("pase segur soloDelante");
											
											jugPase = tec.paseSegur(jug, 20);
											
											if(jug.numero != jugPase && tec.getRondaDeUltimoGol()-tec.getRonda() < -10)
											{
												double[] pase = FutbolTools.pasePreciso(jug, pelotaActual, jugPase);
												
												cmds.add( new ComandoGolpearBola(jug.numero, pase[0], pase[1]) );
											}else if(!tec.getRegateadorEnRonda())
											{
												//log.debug("emPrenenLaPilota!! - despejarASacoPaco");
												cmds.addAll( despejarASacoPaco(jug) );
											}
										}
									}
								}
							}
						}
					}
				}
				else
				{
					cmds.addAll( aPorElla(jug) );
				}
			}
			
			else
			{
				if(tenemos && !tengo)
				{
					if(tec.getAlineacion()[interceptores[0].indiceJugador] instanceof Goalkeeper)
					{
						Point2D.Double p = tec.getPosicionDeDesmarque(jug.numero, jug.fuerza);
						cmds.add( new ComandoIrA(jug.numero,p.x,p.y) );
					}
				}
			
				if(soyMarcador(jug) == true)
				{
					cmds.addAll( marcar(jug) );
				}	
				else
				{
					cmds.addAll( tornaPosicioInicial(jug) );
				}
			}
		}
		
		return cmds;
	}
	
	private Vector<Comando> marcar(Skills jugador)
	{
		Vector<Comando> cmd = new Vector<Comando>();
		int posicion=0;
		for(int i = 0; i<paresMarcaje.length; i++)
		{
			if(jugador.numero ==  paresMarcaje[i][0])
				posicion= i;
		}
		Point2D.Double p = new Point2D.Double();
		p = tec.marcaje(jugador.numero, paresMarcaje[posicion][1], tec.trim(10*(jugador.velocidad-tec.getVelocidadJugadorContrario(paresMarcaje[posicion][1])), 0, 10));
		
		cmd.add(new ComandoIrA(jugador.numero,p.getX(), p.getY()));
		
		//log.debug("Jugador " + jugador.numero + " marca " + paresMarcaje[posicion][1]);
		return cmd;
		
	}
	
	private Vector<Comando> desmarcarme(Skills jugador)
	{
		//log.debug("desmarcarme");
		
		Vector<Comando> cmd = new Vector<Comando>();
		
		Point2D.Double posicion = tec.getPosicionDeDesmarque(jugador.numero, jugador.velocidad);
		
		cmd.add( new ComandoIrA(jugador.numero, posicion.x, posicion.y) );
		
		return cmd;
	}

	private Vector<Comando> aPorElla(Skills jugador)
	{
		//log.debug("aPorElla");
		
		Vector<Comando> cmd = new Vector<Comando>();
		
		Ball pelotaInterceptada = tec.getPelotaAInterceptarTemporal(tec.getTrayectoria(), jugador, jugador.velocidad);
		
		cmd.add( new ComandoIrA(jugador.numero, pelotaInterceptada.x, pelotaInterceptada.y) );
		
		return cmd;
	}

	private boolean emPrenenLaPilota(Skills jugador, int margen)
	{
		double[] posicion = new double[2];
		
		posicion = 	tec.irHaciaConEvasion(	jugador,
											tec.getRutasLibres(jugador, 30, porteriaContraria),
											porteriaContraria);
		
		if(posicion==null)
		{
			//log.debug("posicion == null");
			return true;
		}
		
		Point2D.Double toque = tec.getPosicionDeToque(posicion[0], posicion[1], pelotaActual, margen);
		
		
		double[] toquePos = FutbolTools.toquePreciso(jugador, pelotaActual.getCopia(), toque.x, toque.y);
		
		Ball pelotaHipo = FutbolTools.createPelotaSegunDestino(jugador, jugador.fuerza, pelotaActual, toquePos[0], toquePos[1]);
		
		ArrayList<Ball> tray = new ArrayList<Ball>();
		
		FutbolTools.calculTrajectoria(pelotaHipo, tray);
		
		
		Play h = tec.getMejoresInterceptoresContrariosHipotetico(tray, null)[0];
		
		//log.debug("h: " + h.indicePelota);
		return ( h.indicePelota == 0 );
	}

	private Vector<Comando> regatearAPorteria(Skills jugador)
	{			
		//log.debug("regatearAPorteria");

		Point2D.Double p;
		double[] posicion = new double[2];
		
		Vector<Comando> cmd = new Vector<Comando>();
		
		posicion = 	tec.irHaciaConEvasion(	jugador,
											tec.getRutasLibres(jugador, 30, porteriaContraria),
											porteriaContraria);
		
		if(posicion==null)
		{
			//log.debug("posicion==null -  despejar a saco");
			return despejarASacoPaco(jugador);
		}
		
		cmd.add(new ComandoIrA(jugador.numero, posicion[0], posicion[1]));
		
		p = tec.getPosicionDeToque(posicion[0],posicion[1],pelotaActual,1);
		double[] puntoPreciso = FutbolTools.toquePreciso(jugador, pelotaActual.getCopia(), p.x, p.y);
		
		cmd.add(new ComandoGolpearBola(jugador.numero, puntoPreciso[0], puntoPreciso[1]));

		return cmd;
	}

	private Vector<Comando> despejarASacoPaco(Skills jugador)
	{
		//log.debug("despejarASacoPaco");
		Point2D puntoDespeje = tec.despejarPelota(jugador.numero);
		
		double[] punto = FutbolTools.toquePreciso(jugador, pelotaActual.getCopia(), puntoDespeje.getX(), puntoDespeje.getY());
		
		Vector<Comando> cmd = new Vector<Comando>();
				
		cmd.add( new ComandoGolpearBola(jugador.numero, punto[0],punto[1]) );
		cmd.add( new ComandoIrA(jugador.numero, punto[0],punto[1]) );
		
		return cmd;
	}

	private Vector<Comando> paseSegurRebotadors(Skills jugador)
	{	
		//log.debug("paseSegurRebotadors ...");
		AttSkills rebotador = null;
		int score, scoreAnterior = 999999;
		
		for( AttSkills reb : rebotadors )
		{
			score = tec.contrariEnTrajectoria(jugador, pelotaActual, reb.numero);
			////log.debug("rebotador num " + reb.numero + " a score " + score);
			
			if(score >= 0 && score < scoreAnterior)
			{
				scoreAnterior = score;
				rebotador = reb;
			}
		}
		if(rebotador == null)
			return null;
		else
			if(rebotador.distance(porteriaContraria) > Manager.getDistanciaCritica(rebotador.fuerza) * 1.1)
				return null;
			
		Vector<Comando> cmd = new Vector<Comando>();
		
		double[] rebPase = FutbolTools.pasePreciso(jugador, pelotaActual, rebotador.numero);
		
		cmd.add( new ComandoGolpearBola(jugador.numero, rebPase[0],rebPase[1]) );
		cmd.add( new ComandoIrA(jugador.numero, rebPase[0],rebPase[1]) );

		//log.debug("paseSegurRebotadors si");
		return cmd;
	}
	private Vector<Comando> paseSegurAJugador(Skills jugador)
	{	
		//log.debug("paseSegurAJugador ...");
		Skills[] misJugadores = tec.getAlineacion();
		int score, scoreAnterior = 999999;
		int posicion = 0;
		
		for( int i = 0; i < size(); i++ )
		{
			score = tec.contrariEnTrajectoria(jugador, pelotaActual, misJugadores[i]);
			////log.debug("rebotador num " + reb.numero + " a score " + score);
			
			if(score >= 0 && score < scoreAnterior)
			{
				scoreAnterior = score;
				posicion = i;
			}
		}
		if(posicion == -1)
			return null;
		else
			if(misJugadores[posicion].distance(porteriaContraria) > Manager.getDistanciaCritica(misJugadores[posicion].fuerza) * 1.1)
				return null;
			
		Vector<Comando> cmd = new Vector<Comando>();
		
		double[] rebPase = FutbolTools.pasePreciso(jugador, pelotaActual, misJugadores[posicion].numero);
		
		cmd.add( new ComandoGolpearBola(jugador.numero, rebPase[0],rebPase[1]) );
		cmd.add( new ComandoIrA(jugador.numero, rebPase[0],rebPase[1]) );

		//log.debug("paseSegurAJugador si");
		return cmd;
	}
	private Vector<Comando> paseCriticRebotadors(Skills jugador)
	{
		//log.debug("paseCriticRebotadors ...");
		AttSkills rebotador = rebotadors.elementAt(0);
		
		for( AttSkills reb : rebotadors )
			if(reb.distance(jugador) < rebotador.distance(jugador))
				rebotador = reb;
		
		if( rebotador.distance(jugador) > Manager.getDistanciaCritica(jugador.fuerza) || 
				rebotador.distance(porteriaContraria) > Manager.getDistanciaCritica(rebotador.fuerza) * 1.1)
			return null;
		
		Vector<Comando> cmd = new Vector<Comando>();
		
		double[] rebPase = FutbolTools.pasePreciso(jugador, pelotaActual, rebotador.numero);
		
		cmd.add( new ComandoGolpearBola(jugador.numero, rebPase[0],rebPase[1]) );
		cmd.add( new ComandoIrA(jugador.numero, rebPase[0],rebPase[1]) );
		
		//log.debug("paseCriticRebotadors si");
		return cmd;
	}

	private Vector<Comando> tirSegurPorteria(Skills jugador)
	{
		//log.debug("tirSegurPorteria ...");
		if( tec.contrariEnTrajectoriaPorteria(jugador, pelotaActual) )
			return null;
		
		Vector<Comando> cmd = new Vector<Comando>();
		
		Point2D.Double p = tec.canyonazo(pelotaActual, porteriaContraria.x, porteriaContraria.y);
		
		cmd.add( new ComandoGolpearBola(jugador.numero, p.x, p.y) );
		cmd.add( new ComandoIrA(jugador.numero,p.x,p.y) );
		//log.debug("tirSegurPorteria si");
		return cmd;
	}
	

	private Vector<Comando> tirCriticPorteria(Skills jugador)
	{
		//log.debug("tirCriticPorteria ...");
		
		if( pelotaActual.distance(porteriaContraria) > tec.getDistanciaCritica(jugador.fuerza)-10 )
			return null;
		
		Vector<Comando> cmd = new Vector<Comando>();
		
		Point2D.Double p = tec.canyonazo(pelotaActual, porteriaContraria.x, porteriaContraria.y);
		
		cmd.add( new ComandoGolpearBola(jugador.numero, p.x, p.y) );
		cmd.add( new ComandoIrA(jugador.numero,p.x,p.y) );
		
		//log.debug("tirCriticPorteria si");
		return cmd;
	}

	private Vector<Comando> tornaPosicioInicial(Skills p)
	{
		Vector<Comando> cmd = new Vector<Comando>();
		//log.debug("tornaPosicioInicial");
		cmd.add( new ComandoIrA(p.numero,p.xInicial,p.yInicial));
		return cmd;
	}
	private Comando tornaPosicioInicial1(Skills p)
	{
		return new ComandoIrA(p.numero,p.xInicial,p.yInicial);
	}
	private int[] getContrariosMasCercanosPelota(int num)
	{
		int i;
		//log.debug("getContrariosMasCercanosPelota num: "+ num);
		Point contrarios[] = sj.getContrario();
		double[][] contrariosCercanos = new double[contrarios.length][2];
		int[] contrariosReturn = new int[num];
		
		for(i=0; i<contrarios.length; i++)
		{
			contrariosCercanos[i][0] = i;
			contrariosCercanos[i][1] = pelotaActual.distance(contrarios[i]);
		}
		
		Manager.sort(contrariosCercanos, 1, 2);
		
		System.arraycopy(contrariosCercanos, 0, contrariosCercanos, 0, num);
		
		for(i=0; i<num; i++)
		{
			contrariosReturn[i] = (int) Math.round(contrariosCercanos[i][0]);
		}
		
		return contrariosReturn;
	}
	private int[] getContrariosMasLejanosPelota(int num)
	{
		int i;
		//log.debug("getContrariosMasLejanosPelota num: "+ num);
		Point contrarios[] = sj.getContrario();
		double[][] contrariosCercanos = new double[contrarios.length][2];
		int[] contrariosReturn = new int[num];
		
		for(i=0; i<contrarios.length; i++)
		{
			contrariosCercanos[i][0] = i;
			contrariosCercanos[i][1] = pelotaActual.distance(contrarios[i]);
		}
		
		Manager.sort(contrariosCercanos, 1, 2);
		
		System.arraycopy(contrariosCercanos, 0, contrariosCercanos, 0, num);
		
		for(i=0; i<num; i++)
		{
			contrariosReturn[i] = (int) Math.round(contrariosCercanos[contrariosCercanos.length-1-i][0]);
		}
		
		return contrariosReturn;
	}
	private void rellenarJugadoresQueMarcan()
	{
		//log.debug("rellenarJugadoresQueMarcan");
		
		if(perteneceAEscuadra(interceptores[0].indiceJugador) && perteneceAEscuadra(interceptores[1].indiceJugador))
			jugadoresMarcadores = new int[size()-2];
		else
			if(perteneceAEscuadra(interceptores[0].indiceJugador) || perteneceAEscuadra(interceptores[1].indiceJugador))
			jugadoresMarcadores = new int[size()-1];
			else
				jugadoresMarcadores = new int[size()];
		
		Arrays.fill(jugadoresMarcadores,-1);

		
		
		int inter = 0;
		for(int j=2; j<interceptores.length; j++)
		{
			if( perteneceAEscuadra(interceptores[j].indiceJugador))
			{
				jugadoresMarcadores[inter] = interceptores[j].indiceJugador;
				inter++;
			}
		}
		
		contrariosMarcados = getContrariosMasCercanosPelota(jugadoresMarcadores.length);
		
	}
	private boolean perteneceAEscuadra(int num)
	{
		for( Skills p : this)
			if(p.numero == num)
				return true;
		
		return false;
	}
	private boolean soyMarcador(Skills jug)
	{
		if(getContrariosDentroAreaCritica() != null){
			for(int i = 0; i<paresMarcaje.length; i++)
			{
				if(jug.numero ==  paresMarcaje[i][0])
					return true;
			}
		}
		return false;
	}

	private int[] getContrariosDentroAreaCritica()
	{
		porteria = new Point2D.Double(-160, 0);
		
		Play contrario = null;
		Play[] contrariosPeligrosos = new Play[11];
		int i;
		int anyadidos =0;
		

		for(i=0; i<11; i++){
			//FutbolTools.getDistanciaCritica(tec.getFuerzaJugadorContrario(i))+40
			if( 170 >=
				sj.getContrario()[i].distance(porteria))
			{
				contrario = new Play(i,sj.getContrario()[i],999, new Point(-160,0));
				contrariosPeligrosos[anyadidos++]=contrario;
			}
		}
		
		contrariosPeligrosos = FutbolTools.arrayCopy(contrariosPeligrosos, anyadidos);
		
		if (contrariosPeligrosos.length != 0)
				Arrays.sort(contrariosPeligrosos, new Distance());
		else
			return null;
		int[] contrariosOrdenados = new int[contrariosPeligrosos.length];
		
		for(i=0; i< contrariosPeligrosos.length; i++){
			contrariosOrdenados[i] = contrariosPeligrosos[i].indiceJugador;
			//log.debug("contrariosOrdenados"+ contrariosOrdenados[i]);
		}


	
		return contrariosOrdenados;
		
		
	}

}
